/*--- calcmain.c -------------------------- Listing 8-1 --------
 * Calculator main line for longmath routines.
 *
 * If the program is invoked without any arguments, it responds
 * as an interactive command-line calculator, with all necessary
 * prompts on the screen. Otherwise:
 *
 * If one argument is supplied, it is taken to be a filename,
 * for a calculator script that may contain the following:
 * terms in the prescribed form,
 * the arithemetic operators: +, -, *, /
 * the directive 'C' which clears and resets the calculator to 0
 *
 * In the absence of a clear command, the result of the previous
 * operation is carried over into the first term.
 *
 * If a second file is specified, all terms and operations and
 * their results are written to it; otherwise, the output file
 * is longmath.out
 *------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "longmath.h"

int main(int argc, char *argv[])
{
    struct TermData *term1,     /* two terms and the solution */
                    *term2,
                    *solution;
    
    int operator;
    int format = NORMAL;        /* default to NORMAL notation */

    char buffer[2 * MAX_SIZE];  /* buffer for user input */

    /*--- allocate and initialize the terms ---*/
    term1 = TermCreate();
    term2 = TermCreate();
    solution = TermCreate();

    if (term1 == NULL || term2 == NULL || solution == NULL) {
        fprintf(stderr, "Cannot allocate memory\n");
        return (EXIT_FAILURE);
    }

    /*--- the interactive calculator ---*/
    if (argc < 2) {  /* no input file specified, hence  */
                     /*  it must be interactive.        */
        printf("Arbitrary-Precision Math. Press Q to Quit\n");

        /* get the first term */
        printf("Type first term and press <Enter>\n");
        gets (buffer);
        if (*buffer == 'q' || *buffer == 'Q')
            return (EXIT_SUCCESS);
        else {
            format = AsciiToTerm(buffer, term1);
            if (!format) {
                printf("Invalid term; aborting!\n");
                exit(EXIT_FAILURE);
            }
        }

        /* get the second term */
        printf("Type second term and press <Enter>\n");
        gets(buffer);
        if (*buffer == 'q' || *buffer == 'Q')
            return (EXIT_SUCCESS);
        else {
            format = AsciiToTerm(buffer, term2);
            if (!format) {
                printf("Invalid term; aborting!\n");
                exit(EXIT_FAILURE);
            }
        }

        /* get the desired operation */
        printf("Type operation (+ - * / ) and press <Enter>\n");

        operator = getchar();
        if (operator == 'q' || operator == 'Q')
            return (EXIT_SUCCESS);

        if (operator != '+' && operator != '-' &&
            operator != '*' && operator != '/') {
            printf("Invalid operator; aborting!\n");
            exit(EXIT_FAILURE);
        }

        /*--- compute the result --- */
        if (!ComputeResult(term1, operator, term2, solution))
            return (EXIT_FAILURE);

        /*--- print the answer ---*/
        TermToAscii(solution, buffer, format);

        printf("%s\n", buffer);

        return (EXIT_SUCCESS);
    } else {   /* calculator operations in a file */   
        FILE *fin, *fout;             /* file handles */
        char fin_name[64],            /* file names */
             fout_name[64];

        strcpy(fin_name, argv[1]);
        if (argc > 2)
            strcpy(fout_name, argv[2]);
        else
            strcpy(fout_name, "longmath.out");

        fin = fopen(fin_name, "rt");
        if (fin == NULL) {
            fprintf(stderr, "Error opening: %s\n", fin_name);
            return (EXIT_FAILURE);
        }

        fout = fopen(fout_name, "wt");
        if (fout == NULL) {
            fprintf(stderr, "Error opening: %s\n", fout_name);
            return (EXIT_FAILURE);
        }

        while (!feof(fin)) {
            /* get the first term */
            format = GetFileTerm(term1, fin, fout);
            if (!format)
                break;

            /* get the operator */
            if (!GetFileOperator(&operator, fin, fout))
                break;

          continuing:  /* we'll jump to here if further ops */

            /* get next term */
            format = GetFileTerm(term2, fin, fout);
            if (!format)
                break;

            /*
             * if an error occurs in computing, abort *unless*
             * the next operation is a 'clear,' which starts
             * a new calculation.
             */
            if (!ComputeResult(term1, operator, term2, solution)) {
                fprintf(stderr, "Error in Computing.\n");
                fprintf(fout, "Error in Computing.\n");

                if (!GetFileOperator(&operator, fin, fout)) {
                    fprintf(fout, "Aborting...\n");
                    return (EXIT_FAILURE);
                } else if (operator != 'C') {
                    fprintf(fout, "Aborting...\n");
                    return (EXIT_FAILURE);
                } else {   /* next operation was 'clear' */
                    TermInit(term1);
                    TermInit(term2);
                    TermInit(solution);
                    continue;
                }
            } else {
                /* if no error, print the solution */
                TermToAscii(solution, buffer, format);
                fprintf(fout, "=\n%s\n", buffer);

                /* get the next operation */
                if (!GetFileOperator(&operator, fin, fout))
                    break;

                if (operator == 'C') { /* clear = reinit */
                    TermInit(term1);
                    TermInit(term2);
                    TermInit(solution);
                    continue;
                } else {               /* keep going */               
                    TermCopy(term1, solution);
                    TermInit(term2);
                    TermInit(solution);
                    goto continuing;
                }
            }
        }
        fclose(fin);
        fclose(fout);
    }
    
    return (EXIT_SUCCESS);
}

/*--------------------------------------------------------------
 * Get an operator from the input file and check it for errors;
 * write a copy of it to outfile. Returns 0 on error, else 1.
 *------------------------------------------------------------*/
int GetFileOperator(int *operator,
                    FILE *infile, FILE *outfile)
{
    char buffer[MAX_SIZE + 4];
    char *p;

    if (fgets(buffer, MAX_SIZE + 4, infile) == NULL)
        return (0);

    /* replace the CR/LF with a null; check length */
    p = strchr(buffer, '\n');
    if (p == NULL) {
        printf("Error: invalid operator :\n%s\n", buffer);
        fprintf(outfile, "Error: invalid operator :\n%s\n", buffer);
        return (0);
    } else
        *p = '\0';

    *operator = *buffer;

    if (*(buffer + 1) != '\0' ||
        (*operator != '+' &&
         *operator != '-' &&
         *operator != '*' &&
         *operator != '/' &&
         *operator != 'c' &&
         *operator != 'C')) {
        printf("Error: Invalid operator %c\n", *operator);
        fprintf(outfile, "Error: invalid operator :\n%s\n", buffer);
        return (0);
    }

    if (*operator == 'c')
        *operator = 'C';

    fprintf(outfile, "%c\n", *operator);

    return (1);
}

/*--------------------------------------------------------------
 * Get a term from the input file and check it for errors;
 * write a copy of it to outfile. Returns 0 on error, else
 * returns SCIENTIFIC or NORMAL, indicating the number format.
 *------------------------------------------------------------*/
int GetFileTerm(struct TermData *t,
                FILE *infile, FILE *outfile)
{
    char buffer[MAX_SIZE + 4];
    char *p;
    int format = NORMAL;

    if (fgets(buffer, MAX_SIZE + 4, infile) == NULL)
        return (0);   /* EOF */

    /* replace the CR/LF with a null; check length */
    p = strchr(buffer, '\n');
    if (p == NULL) {
        printf("Error: term too long:\n%s\n", buffer);
        fprintf(outfile, "Error: term too long:\n%s\n", buffer);
        return (0);
    } else
        *p = '\0';

    /* convert to term and check length and errors */
    format = AsciiToTerm(buffer, t);
    if (t->sign == 0 ||
        (t->places_before + t->places_after > MAX_SIZE)) {
        printf("Error: term too long or invalid:\n%s\n", buffer);
        fprintf(outfile, "Error: term too long or invalid:\n%s\n", buffer);
        return (0);
    }

    fprintf(outfile, "%s\n", buffer);
    return (format);
}
